
%{
  open Types

%}

%token Token_LPar Token_RPar

%token <int> Token_Num
%token <string> Token_Var
%token <bool> Token_Bool

%token Token_Skip
%token Token_Assign
%token Token_Seq
%token Token_If Token_Then Token_Else
%token Token_While Token_Do

%token Token_Incr Token_Decr

%token Token_Plus Token_Minus
%token Token_Mult Token_Div
%token Token_Pow
%token Token_Not
%token Token_And
%token Token_Or
%token Token_Equal Token_NotEqual
%token Token_Less Token_LessEqual Token_Greater Token_GreaterEqual

%left Token_Or
%left Token_And
%nonassoc Token_Not
%nonassoc Token_Less Token_LessEqual Token_Greater Token_GreaterEqual Token_Equal Token_NotEqual
%left Token_Plus Token_Minus
%left Token_Mult Token_Div
%nonassoc UnarySign

%token Token_EOF

%start make_prog             /* Entry point */

%type  <Types.prog> make_prog

%%

make_prog:
  | prog Token_EOF                      {$1}

prog:
  | prog Token_Seq prog                 {Seq($1,$3)}

  | Token_LPar prog Token_RPar          {$2}

  | Token_Skip                           {counter := !counter + 1 ; Skip(!counter)}

  | Token_Var Token_Assign expr          {counter := !counter + 1 ; Assign(Var($1),$3, !counter)}

  | Token_While expr
      Token_Do prog
                                         {counter := !counter + 1 ; While($2,$4, !counter)}
  | Token_If expr
      Token_Then prog
      Token_Else prog
                                         {counter := !counter + 1 ; If($2,$4,$6, !counter)}

  | Token_If expr
      Token_Then prog 
                                         {counter := !counter + 1 ; let save = !counter in counter := !counter + 1 ;
                                          If($2,$4,Skip(!counter), save)}

expr:
  | expr Token_And expr              {Expr_And($1, $3)}
  | expr Token_Or  expr              {Expr_Or($1, $3)}
  | expr Token_Equal expr            {Expr_Equal($1,$3)}
  | expr Token_NotEqual expr         {Expr_NotEqual($1, $3)}
  | expr Token_Less expr             {Expr_Less($1,$3)}
  | expr Token_LessEqual expr        {Expr_LessEqual($1, $3)}
  | expr Token_Greater expr          {Expr_Greater($1, $3)}
  | expr Token_GreaterEqual expr     {Expr_GreaterEqual($1, $3)}
  | expr Token_Plus expr             {Expr_Plus($1,$3)}
  | expr Token_Minus expr            {Expr_Minus($1,$3)}
  | expr Token_Mult expr             {Expr_Mult($1,$3)}
  | expr Token_Div expr              {Expr_Div($1, $3)}
  | expr Token_Pow expr              {Expr_Pow($1, $3)}
  | Token_Not expr                   {Expr_Not($2)}
  | Token_Plus  expr %prec UnarySign {$2}
  | Token_Minus expr %prec UnarySign {Expr_Neg($2)}
  | Token_Num                        {Expr_Num($1)}
  | Token_Bool                       {Expr_Bool($1)}
  | Token_Var                        {Expr_Var(Var $1)}
  | Token_LPar expr Token_RPar       {$2}

%%
